/*
    This file is part of the substandard lisp implementation of Standard Lisp
    Copyright (C) 2011 Nicky Nickell

    substandard lisp is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    builtin predicates as defined in section 3.1 of the 
    The Standard Lisp Report
*/

function std_atom(a, env) {
  var u = a[0];

  return type_check(u.type, CLASS_ATOM) ? T : NIL;
}
builtins['atom'] = new builtin_function(std_atom, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_codep(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_FUNCTION) ? T : NIL;
}
builtins['codep'] = new builtin_function(std_codep, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_constantp(a, env) {
  var u = a[0];

  return type_check(u.type, CLASS_CONSTANT) ? T : NIL;
}
builtins['constantp'] = new builtin_function(std_constantp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_eq(a, env) {
  var u = a[0];
  var v = a[1];

  return (u == v) ? T : NIL;
}
builtins['eq'] = new builtin_function(std_eq, 2, false, [CLASS_ANY, CLASS_ANY], FTYPE_EXPR);

function std_eqn(a, env) {
  var u = a[0];
  var v = a[1];

  if (u == v) {
    return T;
  }

  if (type_check(u.type, CLASS_NUMBER) && type_check(v.type, CLASS_NUMBER)) {
    if (u.type == TYPE_INTEGER && v.type == TYPE_INTEGER) {
      return (u.value.compare(v.value) == 0) ? T : NIL;
    } else if (u.type == TYPE_FLOATING && v.type == TYPE_FLOATING) {
      return (v.value == u.value) ? T : NIL;
    } else {
      return NIL;
    }
  } else {
    return NIL;
  }
}
builtins['eqn'] = new builtin_function(std_eqn, 2, false, [CLASS_ANY, CLASS_ANY], FTYPE_EXPR);

function std_equal(a, env) {
  var u = a[0];
  var v = a[1];

  if (std_eqn([u, v], env) == T) {
    return T;
  }

  switch (u.type) {
  case TYPE_STRING:
    return (u.value == v.value) ? T : NIL;
  case TYPE_VECTOR:
    if (u.value.length != v.value.length) {
      return NIL;
    } else {
      for (var i = 0; i < u.value.length; i++) {
        if (std_equal([u.value[i], v.value[i]], env) == NIL) {
          return NIL;
        }
      }
      return T;
    }
  case TYPE_PAIR:
    if (std_equal([u.car, v.car], env) == NIL) {
      return NIL;
    } else {
      return std_equal([u.cdr, v.cdr], env);
    }
  }

  return NIL;
}
builtins['equal'] = new builtin_function(std_equal, 2, false, [CLASS_ANY, CLASS_ANY], FTYPE_EXPR);

function std_fixp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_INTEGER) ? T : NIL;
}
builtins['fixp'] = new builtin_function(std_fixp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_floatp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_FLOATING) ? T : NIL;
}
builtins['floatp'] = new builtin_function(std_floatp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_idp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_ID) ? T : NIL;
}
builtins['idp'] = new builtin_function(std_idp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_minusp(a, env) {
  var u = a[0];

  if (type_check(u.type, CLASS_NUMBER)) {
    return (u.value < 0) ? T : NIL;
  } else {
    return NIL;
  }
}
builtins['minusp'] = new builtin_function(std_minusp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_null(a, env) {
  var u = a[0];

  return (u == NIL) ? T : NIL;
}
builtins['null'] = new builtin_function(std_null, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_numberp(a, env) {
  var u = a[0];

  return type_check(u.type, CLASS_NUMBER) ? T : NIL;
}
builtins['numberp'] = new builtin_function(std_numberp, 1, false, [CLASS_ANY, CLASS_ANY], FTYPE_EXPR);

function std_onep(a, env) {
  var u = a[0];

  if (type_check(u.type, CLASS_NUMBER)) {
    return (u.value == 1) ? T : NIL;
  } else {
    return NIL;
  }
}
builtins['onep'] = new builtin_function(std_onep, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_pairp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_PAIR) ? T : NIL;
}
builtins['pairp'] = new builtin_function(std_pairp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_stringp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_STRING) ? T : NIL;
}
builtins['stringp'] = new builtin_function(std_stringp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_vectorp(a, env) {
  var u = a[0];

  return type_check(u.type, TYPE_VECTOR) ? T : NIL;
}
builtins['vectorp'] = new builtin_function(std_vectorp, 1, false, [CLASS_ANY], FTYPE_EXPR);

function std_zerop(a, env) {
  var u = a[0];

  if (type_check(u.type, CLASS_NUMBER)) {
    return (u.value == 0) ? T : NIL;
  } else {
    return NIL;
  }
}
builtins['zerop'] = new builtin_function(std_zerop, 1, false, [CLASS_ANY], FTYPE_EXPR);
